home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / cpp.arc / CPP2.C < prev    next >
C/C++ Source or Header  |  1985-11-27  |  21KB  |  638 lines

  1.  
  2. /*
  3.  *                              C P P 2 . C
  4.  *
  5.  *                         Process #control lines
  6.  *
  7.  * Edit history
  8.  * 13-Nov-84    MM      Split from cpp1.c
  9.  * 06-Jun-85    KR      fixed #include bug in doinclude()
  10.  */
  11.  
  12. #include        <stdio.h>
  13. #include        <ctype.h>
  14. #include        "cppdef.h"
  15. #include        "cpp.h"
  16. #if HOST == SYS_VMS
  17. /*
  18.  * Include the rms stuff.  (We can't just include rms.h as it uses the
  19.  * VaxC-specific library include syntax that Decus CPP doesn't support.
  20.  * By including things by hand, we can CPP ourself.)
  21.  */
  22. #include        <nam.h>
  23. #include        <fab.h>
  24. #include        <rab.h>
  25. #include        <rmsdef.h>
  26. #endif
  27.  
  28. /*
  29.  * Generate (by hand-inspection) a set of unique values for each control
  30.  * operator.  Note that this is not guaranteed to work for non-Ascii
  31.  * machines.  CPP won't compile if there are hash conflicts.
  32.  */
  33.  
  34. #define L_assert        ('a' + ('s' << 1))
  35. #define L_define        ('d' + ('f' << 1))
  36. #define L_elif          ('e' + ('i' << 1))
  37. #define L_else          ('e' + ('s' << 1))
  38. #define L_endif         ('e' + ('d' << 1))
  39. #define L_if            ('i' + (EOS << 1))
  40. #define L_ifdef         ('i' + ('d' << 1))
  41. #define L_ifndef        ('i' + ('n' << 1))
  42. #define L_include       ('i' + ('c' << 1))
  43. #define L_line          ('l' + ('n' << 1))
  44. #define L_nogood        (EOS + (EOS << 1))      /* To catch #i          */
  45. #define L_pragma        ('p' + ('a' << 1))
  46. #define L_undef         ('u' + ('d' << 1))
  47. #if DEBUG
  48. #define L_debug         ('d' + ('b' << 1))      /* #debug               */
  49. #endif
  50.  
  51. int
  52. control(counter)
  53. int             counter;        /* Pending newline counter              */
  54. /*
  55.  * Process #control lines.  Simple commands are processed inline,
  56.  * while complex commands have their own subroutines.
  57.  *
  58.  * The counter is used to force out a newline before #line, and
  59.  * #pragma commands.  This prevents these commands from ending up at
  60.  * the end of the previous line if cpp is invoked with the -C option.
  61.  */
  62. {
  63.         register int            c;
  64.         register char           *tp;
  65.         register int            hash;
  66.         char                    *ep;
  67.  
  68.         c = skipws();
  69.         if (c == '\n' || c == EOF_CHAR)
  70.             return (counter + 1);
  71.         if (!isdigit(c))
  72.             scanid(c);                  /* Get #word to token[]         */
  73.         else {
  74.             unget();                    /* Hack -- allow #123 as a      */
  75.             strcpy(token, "line");      /* synonym for #line 123        */
  76.         }
  77.         hash = (token[1] == EOS) ? L_nogood : (token[0] + (token[2] << 1));
  78.         switch (hash) {
  79.         case L_assert:  tp = "assert";          break;
  80.         case L_define:  tp = "define";          break;
  81.         case L_elif:    tp = "elif";            break;
  82.         case L_else:    tp = "else";            break;
  83.         case L_endif:   tp = "endif";           break;
  84.         case L_if:      tp = "if";              break;
  85.         case L_ifdef:   tp = "ifdef";           break;
  86.         case L_ifndef:  tp = "ifndef";          break;
  87.         case L_include: tp = "include";         break;
  88.         case L_line:    tp = "line";            break;
  89.         case L_pragma:  tp = "pragma";          break;
  90.         case L_undef:   tp = "undef";           break;
  91. #if DEBUG
  92.         case L_debug:   tp = "debug";           break;
  93. #endif
  94.         default:        hash = L_nogood;
  95.         case L_nogood:  tp = "";                break;
  96.         }
  97.         if (!streq(tp, token))
  98.             hash = L_nogood;
  99.         /*
  100.          * hash is set to a unique value corresponding to the
  101.          * control keyword (or L_nogood if we think it's nonsense).
  102.          */
  103.         if (infile->fp == NULL)
  104.             cwarn("Control line \"%s\" within macro expansion", token);
  105.         if (!compiling) {                       /* Not compiling now    */
  106.             switch (hash) {
  107.             case L_if:                          /* These can't turn     */
  108.             case L_ifdef:                       /*  compilation on, but */
  109.             case L_ifndef:                      /*   we must nest #if's */
  110.                 if (++ifptr >= &ifstack[BLK_NEST])
  111.                     goto if_nest_err;
  112.                 *ifptr = 0;                     /* !WAS_COMPILING       */
  113.             case L_line:                        /* Many                 */
  114.             /*
  115.              * Are pragma's always processed?
  116.              */
  117.             case L_pragma:                      /*  options             */
  118.             case L_include:                     /*   are uninteresting  */
  119.             case L_define:                      /*    if we             */
  120.             case L_undef:                       /*     aren't           */
  121.             case L_assert:                      /*      compiling.      */
  122. dump_line:      skipnl();                       /* Ignore rest of line  */
  123.                 return (counter + 1);
  124.             }
  125.         }
  126.         /*
  127.          * Make sure that #line and #pragma are output on a fresh line.
  128.          */
  129.         if (counter > 0 && (hash == L_line || hash == L_pragma)) {
  130.             putchar('\n');
  131.             counter--;
  132.         }
  133.         switch (hash) {
  134.         case L_line:
  135.             /*
  136.              * Parse the line to update the line number and "progname"
  137.              * field and line number for the next input line.
  138.              * Set wrongline to force it out later.
  139.              */
  140.             c = skipws();
  141.             workp = work;                       /* Save name in work    */
  142.             while (c != '\n' && c != EOF_CHAR) {
  143.                 save(c);
  144.                 c = get();
  145.             }
  146.             unget();
  147.             save(EOS);
  148.             /*
  149.              * Split #line argument into <line-number> and <name>
  150.              * We subtract 1 as we want the number of the next line.
  151.              */
  152.             line = atoi(work) - 1;              /* Reset line number    */
  153.             for (tp = work; isdigit(*tp) || type[*tp] == SPA; tp++)
  154.                 ;                               /* Skip over digits     */
  155.             if (*tp != EOS) {                   /* Got a filename, so:  */
  156.                 if (*tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL) {
  157.                     tp++;                       /* Skip over left quote */
  158.                     *ep = EOS;                  /* And ignore right one */
  159.                 }
  160.                 if (infile->progname != NULL)   /* Give up the old name */
  161.                     free(infile->progname);     /* if it's allocated.   */
  162.                 infile->progname = savestring(tp);
  163.             }
  164.             wrongline = TRUE;                   /* Force output later   */
  165.             break;
  166.  
  167.         case L_include:
  168.             doinclude();
  169.             break;
  170.  
  171.         case L_define:
  172.             dodefine();
  173.             break;
  174.  
  175.         case L_undef:
  176.             doundef();
  177.             break;
  178.  
  179.         case L_else:
  180.             if (ifptr == &ifstack[0])
  181.                 goto nest_err;
  182.             else if ((*ifptr & ELSE_SEEN) != 0)
  183.                 goto else_seen_err;
  184.             *ifptr |= ELSE_SEEN;
  185.             if ((*ifptr & WAS_COMPILING) != 0) {
  186.                 if (compiling || (*ifptr & TRUE_SEEN) != 0)
  187.                     compiling = FALSE;
  188.                 else {
  189.                     compiling = TRUE;
  190.                 }
  191.             }
  192.             break;
  193.  
  194.         case L_elif:
  195.             if (ifptr == &ifstack[0])
  196.                 goto nest_err;
  197.             else if ((*ifptr & ELSE_SEEN) != 0) {
  198. else_seen_err:  cerror("#%s may not follow #else", token);
  199.                 goto dump_line;
  200.             }
  201.             if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING) {
  202.                 compiling = FALSE;              /* Done compiling stuff */
  203.                 goto dump_line;                 /* Skip this clause     */
  204.             }
  205.             doif(L_if);
  206.             break;
  207.  
  208.         case L_if:
  209.         case L_ifdef:
  210.         case L_ifndef:
  211.             if (++ifptr >= &ifstack[BLK_NEST])
  212. if_nest_err:    cfatal("Too many nested #%s statements", token);
  213.             *ifptr = WAS_COMPILING;
  214.             doif(hash);
  215.             break;
  216.  
  217.         case L_endif:
  218.             if (ifptr == &ifstack[0]) {
  219. nest_err:       cerror("#%s must be in an #if", token);
  220.                 goto dump_line;
  221.             }
  222.             if (!compiling && (*ifptr & WAS_COMPILING) != 0)
  223.                 wrongline = TRUE;
  224.             compiling = ((*ifptr & WAS_COMPILING) != 0);
  225.             --ifptr;
  226.             break;
  227.  
  228.         case L_assert:
  229.             if (eval() == 0)
  230.                 cerror("Preprocessor assertion failure", NULLST);
  231.             break;
  232.  
  233.         case L_pragma:
  234.             /*
  235.              * #pragma is provided to pass "options" to later
  236.              * passes of the compiler.  cpp doesn't have any yet.
  237.              */
  238.             printf("#pragma ");
  239.             while ((c = get()) != '\n' && c != EOF_CHAR)
  240.                 cput(c);
  241.             unget();
  242.             break;
  243.  
  244. #if DEBUG
  245.         case L_debug:
  246.             c = skipws();
  247.             unget();
  248.             c = (isdigit(c)) ? eval() : 1;
  249.             if (debug == 0)
  250.                 dumpdef("debug set on");
  251.             debug = c;
  252.             break;
  253. #endif
  254.  
  255.         default:
  256.             /*
  257.              * Undefined #control keyword.
  258.              * Note: the correct behavior may be to warn and
  259.              * pass the line to a subsequent compiler pass.
  260.              * This would allow #asm or similar extensions.
  261.              */
  262.             cerror("Illegal # command \"%s\"", token);
  263.             break;
  264.         }
  265.         if (hash != L_include) {
  266. #if OK_IF_JUNK
  267.             /*
  268.              * Ignore the rest of the #control line so you can write
  269.              *          #if     foo
  270.              *          #endif  foo
  271.              */
  272.             skipnl();
  273. #else
  274.             if (skipws() != '\n') {
  275.                 cwarn("Unexpected text in #control line ignored", NULLST);
  276.                 skipnl();
  277.             }
  278. #endif
  279.         }
  280.         return (counter + 1);
  281. }
  282.  
  283.  
  284.  
  285.  
  286.  
  287.  
  288.  
  289.  
  290.  
  291.  
  292.  
  293.  
  294.  
  295.  
  296.  
  297.  
  298.  
  299.  
  300.  
  301.  
  302.  
  303.  
  304.  
  305. FILE_LOCAL
  306. doif(hash)
  307. int             hash;
  308. /*
  309.  * Process an #if, #ifdef, or #ifndef.  The latter two are straightforward,
  310.  * while #if needs a subroutine of its own to evaluate the expression.
  311.  *
  312.  * doif() is called only if compiling is TRUE.  If false, compilation
  313.  * is always supressed, so we don't need to evaluate anything.  This
  314.  * supresses unnecessary warnings.
  315.  */
  316. {
  317.         register int            c;
  318.         register int            found;
  319.  
  320.         if ((c = skipws()) == '\n' || c == EOF_CHAR) {
  321.             unget();
  322.             goto badif;
  323.         }
  324.         if (hash == L_if) {
  325.             unget();
  326.             found = (eval() != 0);      /* Evaluate expr, != 0 is  TRUE */
  327.             hash = L_ifdef;             /* #if is now like #ifdef       */
  328.         }
  329.         else {
  330.             if (type[c] != LET)         /* Next non-blank isn't letter  */
  331.                 goto badif;             /* ... is an error              */
  332.             found = (lookid(c) != NULL); /* Look for it in symbol table */
  333.         }
  334.         if (found == (hash == L_ifdef)) {
  335.             compiling = TRUE;
  336.             *ifptr |= TRUE_SEEN;
  337.         }
  338.         else {
  339.             compiling = FALSE;
  340.         }
  341.         return;
  342.  
  343. badif:  cerror("#if, #ifdef, or #ifndef without an argument", NULLST);
  344. #if !OK_IF_JUNK
  345.         skipnl();                               /* Prevent an extra     */
  346.         unget();                                /* Error message        */
  347. #endif
  348.         return;
  349. }
  350.  
  351.  
  352.  
  353. FILE_LOCAL
  354. doinclude()
  355. /*
  356.  * Process the #include control line.
  357.  * There are three variations:
  358.  *      #include "file"         search somewhere relative to the
  359.  *                              current source file, if not found,
  360.  *                              treat as #include <file>.
  361.  *      #include <file>         Search in an implementation-dependent
  362.  *                              list of places.
  363.  *      #include token          Expand the token, it must be one of
  364.  *                              "file" or <file>, process as such.
  365.  *
  366.  * Note: the November 12 draft forbids '>' in the #include <file> format.
  367.  * This restriction is unnecessary and not implemented.
  368.  */
  369. {
  370.         register int            c;
  371.         register int            delim;
  372. #if HOST == SYS_VMS
  373.         char                    def_filename[NAM$C_MAXRSS + 1];
  374. #endif
  375.  
  376.         delim = macroid(skipws());
  377.         if (delim != '<' && delim != '"')
  378.             goto incerr;
  379.         if (delim == '<')
  380.             delim = '>';
  381.         workp = work;
  382.         instring = TRUE;                /* Accept all characters        */
  383.         while ((c = get()) != '\n' && c != EOF_CHAR)
  384.             save(c);                    /* Put it away.                 */
  385.         unget();                        /* Force nl after includee      */
  386.         /*
  387.          * The draft is unclear if the following should be done.
  388.          */
  389. #if OK_IF_JUNK
  390.         while (--workp >= work && *workp == ' ')
  391.             ;                           /* Trim blanks from filename    */
  392. #else
  393.         --workp;
  394. #endif
  395.         if (*workp != delim)
  396.             goto incerr;
  397.         *workp = EOS;                   /* Terminate filename           */
  398.         instring = FALSE;
  399. #if HOST == SYS_VMS
  400.         /*
  401.          * Assume the default .h filetype.
  402.          */
  403.         if (!vmsparse(work, ".H", def_filename)) {
  404.             perror(work);               /* Oops.                        */
  405.             goto incerr;
  406.         }
  407.         else if (openinclude(def_filename, (delim == '"')))
  408.             return;
  409. #else
  410.         if (openinclude(work, (delim == '"')))
  411.             return;
  412. #endif
  413.         /*
  414.          * No sense continuing if #include file isn't there.
  415.          */
  416.         cfatal("Cannot open include file \"%s\"", work);
  417.  
  418. incerr: cerror("#include syntax error", NULLST);
  419.         return;
  420. }
  421.  
  422.  
  423.  
  424.  
  425. FILE_LOCAL int
  426. openinclude(filename, searchlocal)
  427. char            *filename;              /* Input file name              */
  428. int             searchlocal;            /* TRUE if #include "file"      */
  429. /*
  430.  * Actually open an include file.  This routine is only called from
  431.  * doinclude() above, but was written as a separate subroutine for
  432.  * programmer convenience.  It searches the list of directories
  433.  * and actually opens the file, linking it into the list of
  434.  * active files.  Returns TRUE if the file was opened, FALSE
  435.  * if openinclude() fails.  No error message is printed.
  436.  */
  437. {
  438.         register char           **incptr;
  439. #if HOST == SYS_VMS
  440. #if NWORK < (NAM$C_MAXRSS + 1)
  441.     << error, NWORK isn't greater than NAM$C_MAXRSS >>
  442. #endif
  443. #endif
  444.         char                    tmpname[NWORK]; /* Filename work area   */
  445.  
  446.         if (searchlocal) {
  447.             /*
  448.              * Look in local directory first
  449.              */
  450. #if HOST == SYS_UNIX
  451.             /*
  452.              * Try to open filename relative to the directory of the current
  453.              * source file (as opposed to the current directory). (ARF, SCK).
  454.              */
  455.             if (filename[0] != '/'
  456.              && hasdirectory(infile->filename, tmpname))
  457.                 strcat(tmpname, filename);
  458.             else {
  459.                 strcpy(tmpname, filename);
  460.             }
  461. #else
  462.             if (!hasdirectory(filename, tmpname)
  463.              && hasdirectory(infile->filename, tmpname))
  464.                 strcat(tmpname, filename);
  465.             else {
  466.                 strcpy(tmpname, filename);
  467.             }
  468. #endif
  469.             if (openfile(tmpname))
  470.                 return (TRUE);
  471.         }
  472.         /*
  473.          * Look in any directories specified by -I command line
  474.          * arguments, then in the builtin search list.
  475.          */
  476.         for (incptr = incdir; incptr < incend; incptr++) {
  477.             if (strlen(*incptr) + strlen(filename) >= (NWORK - 1))
  478.                 cfatal("Filename work buffer overflow", NULLST);
  479.             else {
  480. #if HOST == SYS_UNIX
  481.                 if (filename[0] == '/')
  482.                     strcpy(tmpname, filename);
  483.                 else {
  484.                     sprintf(tmpname, "%s/%s", *incptr, filename);
  485.                 }
  486. #else
  487.                 if (!hasdirectory(filename, tmpname))
  488.                     sprintf(tmpname, "%s%s", *incptr, filename);
  489. #endif
  490.                 if (openfile(tmpname))
  491.                     return (TRUE);
  492.             }
  493.         }
  494.         return (FALSE);
  495. }
  496.  
  497.  
  498.  
  499.  
  500.  
  501.  
  502.  
  503.  
  504.  
  505.  
  506.  
  507.  
  508.  
  509.  
  510.  
  511.  
  512.  
  513.  
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521. FILE_LOCAL int
  522. hasdirectory(source, result)
  523. char            *source;        /* Directory to examine                 */
  524. char            *result;        /* Put directory stuff here             */
  525. /*
  526.  * If a device or directory is found in the source filename string, the
  527.  * node/device/directory part of the string is copied to result and
  528.  * hasdirectory returns TRUE.  Else, nothing is copied and it returns FALSE.
  529.  */
  530. {
  531. #if HOST == SYS_UNIX
  532.         register char           *tp;
  533.  
  534.         if ((tp = strrchr(source, '/')) == NULL)
  535.             return (FALSE);
  536.         else {
  537.             strncpy(result, source, tp - source + 1);
  538.             result[tp - source + 1] = EOS;
  539.             return (TRUE);
  540.         }
  541. #else
  542. #if HOST == SYS_VMS
  543.         if (vmsparse(source, NULLST, result)
  544.          && result[0] != EOS)
  545.             return (TRUE);
  546.         else {
  547.             return (FALSE);
  548.         }
  549. #else
  550.         /*
  551.          * Random DEC operating system (RSX, RT11, RSTS/E)
  552.          */
  553.         register char           *tp;
  554.  
  555.         if ((tp = strrchr(source, ']')) == NULL
  556.          && (tp = strrchr(source, ':')) == NULL)
  557.             return (FALSE);
  558.         else {
  559.             strncpy(result, source, tp - source + 1);
  560.             result[tp - source + 1] = EOS;
  561.             return (TRUE);
  562.         }
  563. #endif
  564. #endif
  565. }
  566.  
  567.  
  568.  
  569. #if HOST == SYS_VMS
  570.  
  571. FILE_LOCAL int
  572. vmsparse(source, defstring, result)
  573. char            *source;
  574. char            *defstring;     /* non-NULL -> default string.          */
  575. char            *result;        /* Size is at least NAM$C_MAXRSS + 1    */
  576. /*
  577.  * Parse the source string, applying the default (properly, using
  578.  * the system parse routine), storing it in result.
  579.  * TRUE if it parsed, FALSE on error.
  580.  *
  581.  * If defstring is NULL, there are no defaults and result gets
  582.  * (just) the node::[directory] part of the string (possibly "")
  583.  */
  584. {
  585.         struct FAB      fab = cc$rms_fab;       /* File access block    */
  586.         struct NAM      nam = cc$rms_nam;       /* File name block      */
  587.         char            fullname[NAM$C_MAXRSS + 1];
  588.         register char   *rp;                    /* Result pointer       */
  589.  
  590.         fab.fab$l_nam = &nam;                   /* fab -> nam           */
  591.         fab.fab$l_fna = source;                 /* Source filename      */
  592.         fab.fab$b_fns = strlen(source);         /* Size of source       */
  593.         fab.fab$l_dna = defstring;              /* Default string       */
  594.         if (defstring != NULLST)
  595.             fab.fab$b_dns = strlen(defstring);  /* Size of default      */
  596.         nam.nam$l_esa = fullname;               /* Expanded filename    */
  597.         nam.nam$b_ess = NAM$C_MAXRSS;           /* Expanded name size   */
  598.         if (sys$parse(&fab) == RMS$_NORMAL) {   /* Parse away           */
  599.             fullname[nam.nam$b_esl] = EOS;      /* Terminate string     */
  600.             result[0] = EOS;                    /* Just in case         */
  601.             rp = &result[0];
  602.             /*
  603.              * Remove stuff added implicitly, accepting node names and
  604.              * dev:[directory] strings (but not process-permanent files).
  605.              */
  606.             if ((nam.nam$l_fnb & NAM$M_PPF) == 0) {
  607.                 if ((nam.nam$l_fnb & NAM$M_NODE) != 0) {
  608.                     strncpy(result, nam.nam$l_node, nam.nam$b_node);
  609.                     rp += nam.nam$b_node;
  610.                     *rp = EOS;
  611.                 }
  612.                 if ((nam.nam$l_fnb & NAM$M_EXP_DEV) != 0) {
  613.                     strncpy(rp, nam.nam$l_dev, nam.nam$b_dev);
  614.                     rp += nam.nam$b_dev;
  615.                 }
  616.                 if ((nam.nam$l_fnb & NAM$M_EXP_DIR) != 0) {
  617.                     strncpy(rp, nam.nam$l_dir, nam.nam$b_dir);
  618.                     rp += nam.nam$b_dir;
  619.                     *rp = EOS;
  620.                 }
  621.             }
  622.             if (defstring != NULLST) {
  623.                 strncpy(rp, nam.nam$l_name, nam.nam$b_name + nam.nam$b_type);
  624.                 rp += nam.nam$b_name + nam.nam$b_type;
  625.                 *rp = EOS;
  626.                 if ((nam.nam$l_fnb & NAM$M_EXP_VER) != 0) {
  627.                     strncpy(rp, nam.nam$l_ver, nam.nam$b_ver);
  628.                     rp[nam.nam$b_ver] = EOS;
  629.                 }
  630.             }
  631.             return (TRUE);
  632.         }
  633.         return (FALSE);
  634. }
  635. #endif
  636.  
  637.  
  638.